const XLSX = require('xlsx');
const fs = require('fs');
const path = require('path');

// 引入坐标转换工具
const coordtransform = require('./coordtool');

// 引入turf库用于空间分析
const turf = require('@turf/turf');

/**
 * 读取Excel文件
 * @param {string} filePath - Excel文件路径
 * @returns {Object} - 工作簿对象
 */
function readExcel(filePath) {
    if (!fs.existsSync(filePath)) {
        throw new Error(`文件不存在: ${filePath}`);
    }
    return XLSX.readFile(filePath);
}

/**
 * 将数字转换为6位小数，如果末尾有0则替换为1
 * @param {number} num - 要处理的数字
 * @returns {number} - 处理后的数字
 */
function formatNumberWithTrailingOnes(num) {
    // 处理字符串数字参数，转换为数值类型
    if (typeof num === 'string') {
        // 尝试将字符串转换为数字
        const parsedNum = parseFloat(num);
        // 检查转换是否成功
        if (isNaN(parsedNum)) {
            console.warn(`无法转换为数字: ${num}`);
            throw new Error(`无法转换为数字: ${num}`);
            return num; // 转换失败时返回原字符串
        }
        num = parsedNum;
    }

    // 确保输入是数字类型
    if (typeof num !== 'number' || isNaN(num)) {
        return num; // 非数字类型时返回原值
    }

    // 先转为6位小数的字符串
    let str = num.toFixed(6);

    // 查找小数点的位置
    const dotIndex = str.indexOf('.');
    if (dotIndex === -1) return num; // 没有小数部分

    // 从末尾开始查找连续的0
    let trailingZerosCount = 0;
    for (let i = str.length - 1; i > dotIndex; i--) {
        if (str[i] === '0') {
            trailingZerosCount++;
        } else {
            break;
        }
    }

    // 如果有末尾的0，则替换为1
    if (trailingZerosCount > 0) {
        const beforeTrailingZeros = str.substring(0, str.length - trailingZerosCount);
        const trailingOnes = '1'.repeat(trailingZerosCount);
        str = beforeTrailingZeros + trailingOnes;
    }

    return parseFloat(str);
}

/**
 * 将BD09坐标转换为WGS84坐标，并按要求格式化小数
 * @param {number} bdLon - BD09经度
 * @param {number} bdLat - BD09纬度
 * @returns {Array} - [wgs84经度, wgs84纬度]
 */
function bd09ToWgs84(bdLon, bdLat) {
    // 先将BD09转换为GCJ02
    const [gcjLon, gcjLat] = coordtransform.bd09togcj02(bdLon, bdLat);
    // 再将GCJ02转换为WGS84
    const [wgs84Lon, wgs84Lat] = coordtransform.gcj02towgs84(gcjLon, gcjLat);

    // 格式化数字，确保6位小数，如果末尾有0则替换为1
    return [
        formatNumberWithTrailingOnes(wgs84Lon),
        formatNumberWithTrailingOnes(wgs84Lat)
    ];
}

/**
 * 处理Excel中的坐标数据
 * @param {Object} workbook - 工作簿对象
 * @param {string} jdl - 经度列名
 * @param {string} wdl - 纬度列名
 * @param {string} zbxl - 坐标系列列名
 * @param {string} zbx - 坐标系列要设置的值
 * @returns {Object} - 处理后的工作簿对象
 */
function processCoordinates(workbook, jdl, wdl, zbxl, zbx) {
    if (!jdl) {
        jdl = '经度'
    }
    if (!wdl) {
        wdl = '纬度'
    }
    // 获取第一个工作表
    const sheetName = workbook.SheetNames[0];
    const worksheet = workbook.Sheets[sheetName];

    // 将工作表转换为JSON格式
    const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });

    // 检查是否有数据
    if (jsonData.length === 0) {
        throw new Error('Excel文件中没有数据');
    }

    // 假设第一行是表头
    const headers = jsonData[0];

    // 查找经度、纬度和坐标系列列的索引
    let lonCol = -1;
    let latCol = -1;
    let zbxlCol = -1;

    for (let i = 0; i < headers.length; i++) {
        const header = headers[i];
        if (header && typeof header === 'string') {
            // 忽略空格并转为小写进行比较
            const normalizedHeader = header.trim().toLowerCase();
            if (normalizedHeader === jdl || normalizedHeader.includes(jdl)) {
                lonCol = i;
            } else if (normalizedHeader === wdl || normalizedHeader.includes(wdl)) {
                latCol = i;
            } else if (zbxl && (normalizedHeader === zbxl || normalizedHeader.includes(zbxl))) {
                zbxlCol = i;
            }
        }
    }

    // 检查是否找到经度和纬度列
    if (lonCol === -1 || latCol === -1) {
        throw new Error('未在Excel文件中找到经度和纬度列');
    }

    console.log(`找到经度列在索引 ${lonCol}，纬度列在索引 ${latCol}`);

    // 如果指定了坐标系列列，则记录其位置
    if (zbxl) {
        if (zbxlCol === -1) {
            console.log(`警告：未找到坐标系列列 '${zbxl}'`);
        } else {
            console.log(`找到坐标系列列在索引 ${zbxlCol}`);
        }
    }

    // 处理每一行数据
    let processedCount = 0;
    let formatCount = 0;
    for (let i = 1; i < jsonData.length; i++) {
        const row = jsonData[i];
        // 确保行数据足够长
        if (row.length <= Math.max(lonCol, latCol)) {
            continue;
        }
        let zbxl = row[zbxlCol];
        const bdLon = parseFloat(row[lonCol]);
        const bdLat = parseFloat(row[latCol]);

        if (!isNaN(bdLon) && !isNaN(bdLat) && zbxl == 'BD09坐标系') {
            // 进行坐标转换
            const [wgs84Lon, wgs84Lat] = bd09ToWgs84(bdLon, bdLat);
            // 直接替换原经度和纬度列的值
            row[lonCol] = formatNumberWithTrailingOnes(wgs84Lon);
            row[latCol] = formatNumberWithTrailingOnes(wgs84Lat);

            // 如果指定了坐标系列列并且找到了该列，则设置其值
            if (zbxl && zbxlCol !== -1 && row.length > zbxlCol) {
                row[zbxlCol] = zbx;
            }

            processedCount++;
            formatCount++;
        } else if (!isNaN(bdLon) && !isNaN(bdLat) && zbxl == 'WGS-84坐标系') {
            // 仅格式化经纬度，保持原值不变，只修改小数格式
            row[lonCol] = formatNumberWithTrailingOnes(row[lonCol]);
            row[latCol] = formatNumberWithTrailingOnes(row[latCol]);
            formatCount++;
        }
    }

    console.log(`成功转换了 ${processedCount} 条坐标数据`);
    console.log(`成功格式化了 ${formatCount} 条坐标数据`);
    if (zbxl && zbxlCol !== -1) {
        console.log(`已将坐标系列列的值设置为: ${zbx}`);
    }

    // 创建新的工作表
    const newWorksheet = XLSX.utils.aoa_to_sheet(jsonData);

    // 将新工作表添加到工作簿
    workbook.Sheets[sheetName] = newWorksheet;

    return workbook;
}

/**
 * 仅格式化Excel中的经纬度列，不进行坐标转换
 * @param {Object} workbook - 工作簿对象
 * @param {string} jdl - 经度列名
 * @param {string} wdl - 纬度列名
 * @returns {Object} - 处理后的工作簿对象
 */
function formatCoordinateColumns(workbook, jdl, wdl) {
    if (!jdl) {
        jdl = '经度'
    }
    if (!wdl) {
        wdl = '纬度'
    }
    // 获取第一个工作表
    const sheetName = workbook.SheetNames[0];
    const worksheet = workbook.Sheets[sheetName];

    // 将工作表转换为JSON格式
    const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });

    // 检查是否有数据
    if (jsonData.length === 0) {
        throw new Error('Excel文件中没有数据');
    }

    // 假设第一行是表头
    const headers = jsonData[0];

    // 查找经度和纬度列的索引
    let lonCol = -1;
    let latCol = -1;

    for (let i = 0; i < headers.length; i++) {
        const header = headers[i];
        if (header && typeof header === 'string') {
            // 忽略空格并转为小写进行比较
            const normalizedHeader = header.trim().toLowerCase();
            if (normalizedHeader === jdl || normalizedHeader.includes(jdl)) {
                lonCol = i;
            } else if (normalizedHeader === wdl || normalizedHeader.includes(wdl)) {
                latCol = i;
            }
        }
    }

    // 检查是否找到经度和纬度列
    if (lonCol === -1 || latCol === -1) {
        throw new Error('未在Excel文件中找到经度和纬度列');
    }

    console.log(`找到经度列在索引 ${lonCol}，纬度列在索引 ${latCol}`);

    // 处理每一行数据，只格式化不转换
    let formattedCount = 0;
    for (let i = 1; i < jsonData.length; i++) {
        const row = jsonData[i];
        // 确保行数据足够长
        if (row.length <= Math.max(lonCol, latCol)) {
            continue;
        }

        const lon = parseFloat(row[lonCol]);
        const lat = parseFloat(row[latCol]);

        if (!isNaN(lon) && !isNaN(lat)) {
            // 仅格式化经纬度，保持原值不变，只修改小数格式
            row[lonCol] = formatNumberWithTrailingOnes(lon);
            row[latCol] = formatNumberWithTrailingOnes(lat);
            formattedCount++;
        }
    }

    console.log(`成功格式化了 ${formattedCount} 条坐标数据`);

    // 创建新的工作表
    const newWorksheet = XLSX.utils.aoa_to_sheet(jsonData);

    // 将新工作表添加到工作簿
    workbook.Sheets[sheetName] = newWorksheet;

    return workbook;
}

/**
 * 保存工作簿到Excel文件
 * @param {Object} workbook - 工作簿对象
 * @param {string} filePath - 输出文件路径
 */
function saveExcel(workbook, filePath) {
    XLSX.writeFile(workbook, filePath);
}

/**
 * 主函数 - 坐标转换版本
 */
function mainCoord(inpath, outpath) {
    try {
        // 输入文件路径
        const inputFilePath = path.join(__dirname, 'data', inpath);
        // 输出文件路径
        const outputFilePath = path.join(__dirname, 'data', outpath);

        // 检查并删除已存在的输出文件
        if (fs.existsSync(outputFilePath)) {
            console.log(`发现已存在的输出文件: ${outputFilePath}，正在删除...`);
            fs.unlinkSync(outputFilePath);
        }

        console.log('正在读取Excel文件...');
        const workbook = readExcel(inputFilePath);

        console.log('正在处理坐标数据...');
        // 通过列名查找并处理坐标数据，同时设置坐标系列列的值
        // 这里假设坐标系列列名为'坐标系列'，要设置的值为 'BD09坐标系'-》'WGS-84坐标系'
        const processedWorkbook = processCoordinates(workbook, '经度', '纬度', '坐标系', 'WGS-84坐标系');

        console.log('正在保存处理后的文件...');
        saveExcel(processedWorkbook, outputFilePath);

        console.log(`转换完成！文件已保存至: ${outputFilePath}`);
    } catch (error) {
        console.error('处理过程中发生错误:', error.message);
    }
}

/**
 * 主函数2 - 仅格式化坐标列版本
 * @param {string} inputFile - 输入文件路径
 * @param {string} outputFile - 输出文件路径
 * @param {string} lonColumnName - 经度列名
 * @param {string} latColumnName - 纬度列名
 */
function main2(inputFile, outputFile, lonColumnName = '经度', latColumnName = '纬度') {
    try {
        // 输入文件路径
        const inputFilePath = path.join(__dirname, 'data', inputFile);
        // 输出文件路径
        const outputFilePath = path.join(__dirname, 'data', outputFile);

        console.log('正在读取Excel文件...');
        const workbook = readExcel(inputFilePath);

        console.log('正在格式化坐标数据...');
        // 仅格式化坐标列，不进行坐标转换
        const formattedWorkbook = formatCoordinateColumns(workbook, lonColumnName, latColumnName);

        console.log('正在保存处理后的文件...');
        saveExcel(formattedWorkbook, outputFilePath);

        console.log(`格式化完成！文件已保存至: ${outputFilePath}`);
    } catch (error) {
        console.error('处理过程中发生错误:', error.message);
    }
}

/**
 * 主函数3 - 空间分析打标签版本
 * @param {string} inputFile - 输入文件路径
 * @param {string} outputFile - 输出文件路径
 * @param {string} lonColumnName - 经度列名
 * @param {string} latColumnName - 纬度列名
 * @param {string} geojsonPath - geojson文件路径
 */
function maintag(inputFile, outputFile, lonColumnName = '经度', latColumnName = '纬度', streetColumnName = '所属街道', communityColumnName = '所属社区', geojsonFilePath = 'XZQ_LJSQ_ZS.json', showCount = true) {
    try {
        const geojsonPath = path.join(__dirname, 'xzqdata', geojsonFilePath);
        // 输入文件路径
        const inputFilePath = path.join(__dirname, 'data', inputFile);



        console.log('正在读取Excel文件...');
        const workbook = readExcel(inputFilePath);

        console.log('正在读取GeoJSON文件...');
        // 读取GeoJSON文件
        const geojsonData = JSON.parse(fs.readFileSync(geojsonPath, 'utf8'));

        console.log('正在进行空间分析...');
        // 获取第一个工作表
        const sheetName = workbook.SheetNames[0];
        const worksheet = workbook.Sheets[sheetName];

        // 将工作表转换为JSON格式
        const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });

        // 检查是否有数据
        if (jsonData.length === 0) {
            throw new Error('Excel文件中没有数据');
        }

        // 假设第一行是表头
        let headers = jsonData[0];

        // 查找经度和纬度列的索引
        let lonCol = -1;
        let latCol = -1;
        let streetCol = -1;
        let communityCol = -1;

        for (let i = 0; i < headers.length; i++) {
            const header = headers[i];
            if (header && typeof header === 'string') {
                // 忽略空格并转为小写进行比较
                const normalizedHeader = header.trim().toLowerCase();
                if (normalizedHeader === lonColumnName || normalizedHeader.includes(lonColumnName)) {
                    lonCol = i;
                } else if (normalizedHeader === latColumnName || normalizedHeader.includes(latColumnName)) {
                    latCol = i;
                } else if (normalizedHeader.includes(streetColumnName)) {
                    streetCol = i;
                } else if (normalizedHeader.includes(communityColumnName)) {
                    communityCol = i;
                }
            }
        }

        // 检查是否找到经度和纬度列
        if (lonCol === -1 || latCol === -1) {
            throw new Error('未在Excel文件中找到经度和纬度列');
        }

        // 如果没有街道和社区列，则添加它们
        if (streetCol === -1) {
            throw new Error(`未在Excel文件中找到${streetColumnName}列`);
            headers.push('所属街道');
            streetCol = headers.length - 1;
        }
        if (communityCol === -1) {
            throw new Error(`未在Excel文件中找到${communityColumnName}列`);
            headers.push('所属社区');
            communityCol = headers.length - 1;
        }

        console.log(`找到经度列在索引 ${lonCol}，纬度列在索引 ${latCol}`);
        console.log(`街道列在索引 ${streetCol}，社区列在索引 ${communityCol}`);

        // 处理每一行数据
        let singleHitCount = 0;
        let multiHitCount = 0;
        let noHitCount = 0;

        for (let i = 1; i < jsonData.length; i++) {
            let row = jsonData[i];
            // // 确保行数据足够长
            // if (row.length <= Math.max(lonCol, latCol)) {
            //     continue;
            // }

            // // 确保行数据有足够的列
            // while (row.length <= Math.max(streetCol, communityCol)) {
            //     row.push('');
            // }

            const lon = parseFloat(row[lonCol]);
            const lat = parseFloat(row[latCol]);

            if (!isNaN(lon) && !isNaN(lat)) {
                // 创建点要素
                const point = turf.point([lon, lat]);

                // 检查点与哪些面相交
                const intersectingFeatures = [];

                geojsonData.features.forEach(feature => {
                    try {
                        if (turf.booleanPointInPolygon(point, feature)) {
                            intersectingFeatures.push(feature);
                        }
                    } catch (error) {
                        console.warn(`检查要素相交时出错: ${error.message}`);
                    }
                });

                // 根据相交结果设置街道和社区字段
                if (intersectingFeatures.length === 1) {
                    // 只压盖了一个社区面要素
                    const feature = intersectingFeatures[0];
                    row[streetCol] = feature.properties.JDMC || '';
                    row[communityCol] = feature.properties.XZQHMC || '';
                    singleHitCount++;
                } else if (intersectingFeatures.length > 1) {
                    // 压盖了多个社区面要素
                    row[streetCol] = 'A街道';
                    row[communityCol] = 'A社区';
                    multiHitCount++;
                } else {
                    // 未压盖到任何社区面要素
                    row[streetCol] = 'A街道';
                    row[communityCol] = 'A社区';
                    noHitCount++;
                }
            }
        }

        console.log(`成功处理了 ${singleHitCount + multiHitCount + noHitCount} 条数据`);
        console.log(`其中：`);
        console.log(`  只压盖一个社区面要素: ${singleHitCount} 条`);
        console.log(`  压盖多个社区面要素: ${multiHitCount} 条`);
        console.log(`  未压盖任何社区面要素: ${noHitCount} 条`);

        // 创建新的工作表
        const newWorksheet = XLSX.utils.aoa_to_sheet(jsonData);

        // 将新工作表添加到工作簿
        workbook.Sheets[sheetName] = newWorksheet;

        console.log('正在保存处理后的文件...');
        // 输出文件路径
        if (showCount) {
            outputFile = outputFile.replace(".xlsx", `-${singleHitCount}-${singleHitCount + multiHitCount + noHitCount}.xlsx`)
        }
        const outputFilePath = path.join(__dirname, 'data', outputFile);
        // 检查并删除已存在的输出文件
        if (fs.existsSync(outputFilePath)) {
            console.log(`发现已存在的输出文件: ${outputFilePath}，正在删除...`);
            fs.unlinkSync(outputFilePath);
        }
        saveExcel(workbook, outputFilePath);

        console.log(`空间分析完成！文件已保存至: ${outputFilePath}`);
    } catch (error) {
        console.error('处理过程中发生错误:', error.message);
    }
}

function main1() {
    // 进行坐标转换
    const [gcjLon, gcjLat] = [106.50058, 29.617755];
    const [wgs84Lon, wgs84Lat] = coordtransform.gcj02towgs84(gcjLon, gcjLat);
    console.log(`GCJ02: (${gcjLon}, ${gcjLat}) -> WGS84: (${wgs84Lon}, ${wgs84Lat})`);
}
// main1();
// main2('联网式独立感温火灾探测报警器（意静）WGS84.xlsx', '联网式独立感温火灾探测报警器（意静）WGS84V2.xlsx');

// 执行默认主函数
// mainCoord('组合式感烟（两江消防）.xlsx', '组合式感烟（两江消防）-WGS84.xlsx');

// 示例：执行maintag函数（取消注释使用）
// maintag('组合式感烟（两江消防）-WGS84.xlsx', '组合式感烟（两江消防）-WGS84-tagged.xlsx');

// 导出函数，方便其他模块调用
module.exports = {
    readExcel,
    bd09ToWgs84,
    processCoordinates,
    formatCoordinateColumns,
    saveExcel,
    mainCoord,
    main1,
    main2,
    maintag
};